/* 
	Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 
	
	All rights reserved.
	
	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:
	
	1. Redistributions of source code must retain the above copyright
	   notice, this list of conditions and the following disclaimer.
	
	2. Redistributions in binary form must reproduce the above copyright
	   notice, this list of conditions and the following disclaimer in the
	   documentation and/or other materials provided with the distribution.
	
	3. The name of the author may not be used to endorse or promote products
	   derived from this software without specific prior written permission.
	
	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
	THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {
AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{
	accessext_get_image_objects: function(pageElement) {
		var e = new Array();
		var objects = pageElement.getElementsByTagName('object');
		var isImage = false;
		for (var j=0; j < objects.length; j++) {
			if (objects[j].hasAttribute("type")) {
				var t = objects[j].getAttribute("type").split("/");
				if (t.length > 0) {
					isImage = (t[0].toLowerCase() == 'image');
				}
			}
			if (isImage) {
				e.push(objects[j]);
			}
		}
		return e;
	},
	
	accessext_get_maps: function(pageElement) {
		var m = new Array();
		var e = pageElement.getElementsByTagName('map');
		var i;
		for(i=0; i < e.length; i++) {
			if (e[i].hasAttribute("name")) {
				m[cleanSpaces(e[i].getAttribute("name"))]=e[i];
			} else if (e[i].hasAttribute("id")) {
				m[cleanSpaces(e[i].getAttribute("id"))]=e[i];
			} 
		}
		return m;
	},
	
	// Toggles Images, Objects, Background images simultaneously
	accessext_handle_textequivall_hide: function(checked,doc) {
		accessext_toggle_feature('objects-hide',checked);
		accessext_toggle_feature('images-hide',checked);
		accessext_toggle_feature('images-hide-backgrounds',checked);
	},
	
	accessext_handle_objects_hide: function(checked,doc) {
		var cssid = "accessext-css-hide-objects";
		try {
			accessext_toggle_feature('textequivall-hide',false,false,doc);
			accessext_hideObjects(checked, cssid,doc);
		} catch (ex) {
			accessext_consoleDump('exception: ', ex);
		}
	},
	
	accessext_handle_images_hide: function(checked,doc) {
		var cssid = "accessext-css-hide-images";
		try {
			accessext_toggle_feature('textequivall-hide',false,false,doc);
			accessext_hideImages(checked, cssid,doc);
		} catch (ex) {
			accessext_consoleDump('exception: ', ex);
		}
	},
	
	// doc is an array of document objects upon which to operate
	accessext_hideObjects: function(checked,cssid,doc) {
		var url              = "chrome://accessext/content/css/disable-objects.css";
		var documentList;
		var inputElement     = null;
		var inputElementList = null;
		var pageDocument     = null;
		var j;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
	
		// Loop through the documents
		for(var i = 0; i < documentList.length; i++) {
			pageDocument     = documentList[i];
	
			/* romanows, I think most code in accessext_hideImages was due to a weird situation where images could be used in form inputs.
			 * Since this isn't the case with embedded objects; we just style them out of the page 
			 */
			 		
			accessext_toggleStyleSheet(checked, url, 'accessext-objects-hide-stylesheet',pageDocument);
		}
	},
	
	// doc is an array of document objects upon which to operate
	accessext_hideImages: function(checked,cssid,doc) {
		var url              = "chrome://accessext/content/css/disable-images.css";
		var documentList;
		var inputElement     = null;
		var inputElementList = null;
		var pageDocument     = null;
		var j;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
	
		// Loop through the documents
		for(var i = 0; i < documentList.length; i++) {
			pageDocument     = documentList[i];
			inputElementList = pageDocument.getElementsByTagName("input");
	
			// Loop through all the input tags
			for(j = 0; j < inputElementList.length; j++) {
				inputElement = inputElementList[j];
	
				// If hiding images and the element is an image
				
				if(checked && inputElement.getAttribute("type") == "image") {
					accessext_replaceAttributeWBackup(inputElement,"class","accessext-image",true);
					inputElement.setAttribute("type", "submit");
				}
				else if(inputElement.getAttribute("class") == "accessext-image") {
					accessext_replaceAttributeWBackup(inputElement,"class","accessext-image",false);
					inputElement.setAttribute("type", "image");
				}
			}
			
			//Hide all objects
			
			if (checked) {
				inputElementList = accessext_get_image_objects(pageDocument);
				
				/*
					This is a little different than other methods. Each object has to be renamed if it is an
					image. Renaming automatically removes the element from the list since it is no longer valid.
					We could just push it back onto the list, but this way works as well.
					
					An explicit shift() is done just to make this process clear, but if you were to not do
					the shift, the element still would disappear from inputElementList after the rename
				*/
				while(inputElementList.length > 0) {
					inputElement = inputElementList.shift();
					accessext_rename_node(inputElement,'disabledobject');
				}
			}
			else {
				inputElementList = pageDocument.getElementsByTagName("disabledobject");
				while(inputElementList.length > 0) {
					inputElement = inputElementList[0];
					accessext_rename_node(inputElement,'object');
				}
			}
			accessext_toggleStyleSheet(checked, url, 'accessext-images-hide-stylesheet',pageDocument);
		}
	},
	
	accessext_DOM_insertAfter: function(element,newelement) {
		if (element.nextSibling == null) {
			element.parentNode.appendChild(newelement);
		} else {
			element.parentNode.insertBefore(newelement,element.nextSibling);
		}
	},
	
	accessext_insert_map_contents_common: function(element,map) {
		var areas = map.getElementsByTagName('area');
		var owner = map.ownerDocument;
		var div = owner.createElement('div');
			div.setAttribute('class','accessext-map-div');
		if (areas.length > 0){
			var ul = owner.createElement('ul');
			for (var i=0; i < areas.length; i++) {
				var li = owner.createElement('li');
				var t  = owner.createTextNode(areas[i].hasAttribute('alt') ? cleanSpaces(areas[i].getAttribute('alt')) : accessext_getBundleSingleString('noAlt'));
				if (areas[i].hasAttribute('href')) {
					var a = owner.createElement('a');
					a.setAttribute('href',areas[i].getAttribute('href'));
					a.appendChild(t);
					li.appendChild(a);
				}
				else {
					li.appendChild(t);
				}
				ul.appendChild(li);
			}
			div.appendChild(ul);
		}
		
		accessext_DOM_insertAfter(element,div);
	},
	
	accessext_insert_map_contents: function(e,maps) {
		var usemap;
		if (e.hasAttribute('usemap')) {
			usemap = e.getAttribute('usemap');
			usemap = usemap.replace(/^#(.*)/,"$1");
	
			if (typeof(maps[usemap])!='undefined') {
				var m = maps[usemap];
				accessext_insert_map_contents_common(e,m);
			}
		}
	},
	
	accessext_replace_object_with_map: function(o,maps) {
		accessext_insert_map_contents(o,maps);
		accessext_rename_node(o,'disabledobject');
	},
	
	// Replaces all images with their alt attributes
	accessext_handle_images_replaceWithAlt: function(checked,doc) {
		var altAttribute     = null;
		var documentList;
		var imageElement     = null;
		var imageElementList = null;
		var pageDocument     = null;
		var previousElement  = null;
		var spanElement      = null;
		var cssid            = "accessext-css-replace-images-with-alt";
		var maps 			= null;
		
		var j;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		
		// Loop through the documents
		for(var i = 0; i < documentList.length; i++) {
			pageDocument     = documentList[i];
			imageElementList = pageDocument.getElementsByTagName("img");
			objectElementList = pageDocument.getElementsByTagName("object");
			areaElementList = pageDocument.getElementsByTagName("area");
			embedElementList = pageDocument.getElementsByTagName("embed");
			appletElementList = pageDocument.getElementsByTagName("applet");
			maps = accessext_get_maps(pageDocument);
			
			//xpath??
			for(objectIndex = 0; objectIndex < objectElementList.length; objectIndex++) {
				objectElement = objectElementList[objectIndex];
				objectText = objectElement.innerHTML;
				previousElement = objectElement.previousSibling;
				spanElement = pageDocument.createElement("span");
				
				// If the previous element is an element with class accessext-alt-span
				if(previousElement && previousElement.nodeType == 1 && previousElement.getAttribute("class") == "accessext-alt-span") {
					previousElement.parentNode.removeChild(previousElement);
				}
	
				// If the element is checked and the alt attribute exists
				if(checked && objectText) {
					spanElement.setAttribute("class", "accessext-alt-span");
					spanElement.appendChild(pageDocument.createTextNode(objectText));
					objectElement.parentNode.insertBefore(spanElement, objectElement);
				}
			}
			
			// Loop through all the embed tags
			for(j = 0; j < embedElementList.length; j++) {
				embedElement    = embedElementList[j];
				altAttribute    = embedElement.getAttribute("alt");
				previousElement = embedElement.previousSibling;
				spanElement     = pageDocument.createElement("span");
				
				// If the previous element is an element with class accessext-alt-span
				if(previousElement && previousElement.nodeType == 1 && previousElement.getAttribute("class") == "accessext-alt-span") {
					previousElement.parentNode.removeChild(previousElement);
				}
	
				// If the element is checked and the alt attribute exists
				if(checked && altAttribute) {
					spanElement.setAttribute("class", "accessext-alt-span");
					spanElement.appendChild(pageDocument.createTextNode(altAttribute));
					embedElement.parentNode.insertBefore(spanElement, embedElement);
				}
			}
			
			// Loop through all the applet tags
			for(j = 0; j < appletElementList.length; j++) {
				appletElement    = appletElementList[j];
				altAttribute    = appletElement.getAttribute("alt");
				previousElement = appletElement.previousSibling;
				spanElement     = pageDocument.createElement("span");
				
				// If the previous element is an element with class accessext-alt-span
				if(previousElement && previousElement.nodeType == 1 && previousElement.getAttribute("class") == "accessext-alt-span") {
					previousElement.parentNode.removeChild(previousElement);
				}
	
				// If the element is checked and the alt attribute exists
				if(checked && altAttribute) {
					spanElement.setAttribute("class", "accessext-alt-span");
					spanElement.appendChild(pageDocument.createTextNode(altAttribute));
					appletElement.parentNode.insertBefore(spanElement, appletElement);
				}
			}
			
			// Loop through all the img tags
			for(j = 0; j < imageElementList.length; j++) {
				imageElement    = imageElementList[j];
				altAttribute    = imageElement.getAttribute("alt");
				previousElement = imageElement.previousSibling;
				spanElement     = pageDocument.createElement("span");
				
				// If the previous element is an element with class accessext-alt-span
				if(previousElement && previousElement.nodeType == 1 && previousElement.getAttribute("class") == "accessext-alt-span") {
					previousElement.parentNode.removeChild(previousElement);
				}
	
				// If the element is checked and the alt attribute exists
				if(checked && altAttribute) {
					spanElement.setAttribute("class", "accessext-alt-span");
					spanElement.appendChild(pageDocument.createTextNode(altAttribute));
					imageElement.parentNode.insertBefore(spanElement, imageElement);
				}
				
				//And finally insert map contents if there are any
				accessext_insert_map_contents(imageElement,maps);
			}
			
			//Loop through all objects that have a map element
			if (checked) {
				var inputElementList = accessext_get_image_objects(pageDocument);
				while(inputElementList.length > 0) {
					imageElement = inputElementList.shift();
					accessext_replace_object_with_map(imageElement,maps);
				}
			} else {
				//Look for all divs with a class of accessext-map-div
				//@todo: speedup w/ xpath
				var divs = pageDocument.getElementsByTagName('div');
				j=0;
				while(j < divs.length) {
					var t = divs[j];
					if (t.hasAttribute('class') && t.getAttribute('class')=='accessext-map-div') {
						t.parentNode.removeChild(t);
					} else {
						j++;
					}
				}
			}
		}
		accessext_hideImages(checked, cssid,doc);
		accessext_hideObjects(checked, cssid, doc);
	},
	
	accessext_handle_styles_css_enabled: function(checked,doc) {
		var documentList;
		var pageDocument     = null;
		var styleSheet       = null;
		var styleSheetList   = null;
	
		//Disable all inline styling
		var attributes = new Array('style');
		
		var j;
		var mapping = new Array();
		
		mapping['style-disabled'] = new Array('style');
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
			//accessext_consoleDump('doc');
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
			//accessext_consoleDump('doclist');
		}
		
		/*
			This section deserves somewhat of an explanation
			There is probably a better solution. This one works, and saved time
			waiting for answers on a forum. You are welcome to fix it.
			<style> tags with an @import rule refused to actually disable.
			By inserting alerts into the code, I  determined that the stylesheet
			is acually disabled if the for ... styles.length loop. But, immediately
			following the loop, the styles are turned back on. To prevent this,
			<style> tags are just renamed. This problem only seems to happen
			on @imports inside <style> tags.
		*/	
		// Loop through the documents
		for(var i = 0; i < documentList.length; i++) {
			pageDocument   = documentList[i];
			styleSheetList = pageDocument.styleSheets;
	
			//Disable style attribute
			accessext_disable_attributes_recursively(pageDocument.documentElement,attributes,!checked);
			
			//Disable all <syle> tags
			renamedNodes = new Array();
			accessext_rename_recursively(pageDocument.documentElement,!checked,mapping);
			
			//Disable link rel="stylesheet"
			/*
			One further thing to watch here: Any appended stylesheets (such as disable tables, or the user specified stylesheet)
			gets added as a <link>. All we have to work on is the id="" attribute.
			*/
			var attID;
			var links = pageDocument.getElementsByTagName("link");
			for (j=0; j < links.length; j++) {
				if (!(links[j].hasAttribute("id") && links[j].getAttribute("id").substr(0,15)=="_accessextstyle")) {
					if (links[j].hasAttribute("rel") && links[j].getAttribute("rel").toUpperCase() == "STYLESHEET") {
						attID = links[j].getAttribute("id");
						if ((attID != "accessext-images-hide-stylesheet") && (attID != "accessext-objects-hide-stylesheet") && (attID != "accessext-images-hide-backgrounds") && (attID != "aepref-style.expandAbbr")) {
							if (!checked) {
								links[j].disabled=true;
								links[j].setAttribute("accessext-disabled",true);
							} else if (links[j].hasAttribute("accessext-disabled")) {
								links[j].disabled=false;
								links[j].removeAttribute("accessext-disabled");
							}
						}
					}
				}
			}
		}
	},
	
	accessext_handle_images_disable_backgrounds: function(checked,doc) {
		var url              = "chrome://accessext/content/css/disable-backgrounds.css";
		var documentList;
		var pageDocument = null;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		accessext_toggle_feature('textequivall-hide',false,false,doc);
	
		for(var i = 0; i < documentList.length; i++) {
			pageDocument   = documentList[i];
			accessext_toggleStyleSheet(checked, url, 'accessext-images-hide-backgrounds',pageDocument);
		}
	},
	
	accessext_handle_styles_css_tags_enabled: function(checked,doc) {
		var pTags = new Array();
		var divTags = new Array();
		var ulTags = new Array();
		var spanTags = new Array();	
		
		pTags.push('marquee','blink');
		divTags.push('font','center','color','basefont','s','strike','listing','plaintext','u','xmp','isindex');
		ulTags.push('menu','dir');
		spanTags.push('big','b','i','s','u');
		
		var tagMappings = new Array();
		tagMappings['div']=divTags;
		tagMappings['p']=pTags;
		tagMappings['ul']=ulTags;
		tagMappings['span']=spanTags;
		
		var attributes = new Array();
		attributes.push('face','color','weight','size','bgcolor','align','alink','background','hspace','vlink','vpsace');
		
		var documentList;
		var pageDocument     = null;
	
		var i;
		renamedNodes = new Array();
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		
		for (i=0; i < documentList.length; i++) {
			pageDocument = documentList[i];
			accessext_rename_recursively(pageDocument.documentElement,!checked,tagMappings);
			accessext_disable_attributes_recursively(pageDocument.documentElement,attributes,!checked);
		}
		renamedNodes = new Array();//clear it
	},
	
	
	accessext_handle_styles_setStylesheet_toggle: function(checked,style,prefStr,doc) {
		var url      = "chrome://accessext/content/css/"+style+".css";
		var addid       = "_accessextstyles-" + style;
		
		if(checked) {
			accessext_addStyleSheet(url, addid,doc);
		} else {
			accessext_removeStyleSheet(addid,doc);
		}
	},
	
	/**
	 * Disables CSS and Tag Styling
	 * @param {doc} doc the doc in which to disable CSS and Tag Styling.
	 * @param {bEnable} bEnable if true the menu items are enabled, if false they are disabled
	 * @return nothing
	 * @author Sandy Foltz
	 */
	accessext_enableCSSAndTagStyling : function(style,doc,bEnable) {
		
		var bOppositeHighContrastChecked;
		if (style == 'highcontrast') { // it has not been set yet in the interface
			//accessext-bcast-styles-highcontrast2
			bOppositeHighContrastChecked = document.getElementById('accessext-toolbarbutton-styles-highcontrast2').getAttribute("checked")
		} else {
	 		bOppositeHighContrastChecked = document.getElementById('accessext-toolbarbutton-styles-highcontrast').getAttribute("checked")
		}
	    //accessext_consoleDump('bOppositeHighContrastChecked:' + bOppositeHighContrastChecked);
	
		if ((bOppositeHighContrastChecked == true) && (document.getElementById("accessext-cmd-author-css-enabled").getAttribute("disabled") == true) ){
	 		//accessext_consoleDump('author css ext already disabled');
			return;
		}
			
		if (bEnable == true) {
			if (document.getElementById("accessext-bcast-author-css-enabled").getAttribute("checked") == "true") {
				accessext_handle_styles_css_enabled(true,doc);
			}
			if (document.getElementById("accessext-bcast-css-tags-enabled").getAttribute("checked") == "true") {
				accessext_handle_styles_css_tags_enabled(true,doc);
			}
		} else { //disabeling
			if (document.getElementById("accessext-bcast-author-css-enabled").getAttribute("checked") == "true") {
				accessext_handle_styles_css_enabled(false,doc);
			} 
			if (document.getElementById("accessext-bcast-css-tags-enabled").getAttribute("checked") == "true") {
				accessext_handle_styles_css_tags_enabled(false,doc);
			}	
		}
			
		//enableMenuItem 
		document.getElementById("accessext-cmd-author-css-enabled").setAttribute("disabled",!bEnable);	
		document.getElementById("accessext-cmd-css-tags-enabled").setAttribute("disabled",!bEnable);	
	},
	
	accessext_handle_styles_setStylesheet: function(style,checked,doc) {
		var prefStr = "";
		var id = "";
		var file = "";
	
		accessext_enableCSSAndTagStyling (style,doc,!checked);
		switch(style) {
			case 'highcontrast':
				prefStr = "accessext.styles.highcontrast";
				file="highcontrast";
				
				var documentList;
	
				if((typeof doc != "undefined") && (doc != null)) {
					documentList = doc;
				} else {
					// assume we're doing stuff to the current window
					documentList = accessext_getDocumentsFromActiveBrowser();
				}
		
				var pageDocument     = null;
		
				for (i=0; i < documentList.length; i++) { //for each browser window
					pageDocument = documentList[i];
					accessext_handle_styles_setStylesheet_toggle(checked,"highcontrast2","accessext.styles.highcontrast2",pageDocument);									
					accessext_handle_styles_setStylesheet_toggle(checked,file,prefStr,pageDocument);
				}
				
				//document.getElementById('accessext-bcast-styles-highcontrast2').setAttribute("checked", false);		
				document.getElementById("accessext-cmd-styles-highcontrast2").setAttribute("disabled",checked);	
	
			break;
			case 'highcontrast2':
				prefStr = "accessext.styles.highcontrast2";
				file="highcontrast2";
				
				var documentList;
	
				if((typeof doc != "undefined") && (doc != null)) {
					documentList = doc;
				} else {
					// assume we're doing stuff to the current window
					documentList = accessext_getDocumentsFromActiveBrowser();
				}
	
				var pageDocument     = null;
		
				for (i=0; i < documentList.length; i++) {
					pageDocument = documentList[i];
					accessext_handle_styles_setStylesheet_toggle(checked,"highcontrast","accessext.styles.highcontrast",pageDocument);
					accessext_handle_styles_setStylesheet_toggle(checked,file,prefStr,pageDocument);
				}
				
				//document.getElementById('accessext-bcast-styles-highcontrast').setAttribute("checked", false);
				document.getElementById("accessext-cmd-styles-highcontrast").setAttribute("disabled",checked);	
			break;
	
			default:
				return false;
		}
	
		return true;
	},
	
	accessext_handle_styles_userStylesheet_set: function(id,doc) {
		// If adding a style sheet and applying styles
		var filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
	
		filePicker.appendFilter(accessext_getBundleSingleString('styles.userSheet.openFile.filterText'), "*.css");
		filePicker.init(window, accessext_getBundleSingleString('styles.userSheet.openFile.title'), filePicker.modeOpen);
	
		// If the user selected a style sheet
		if(filePicker.show() == filePicker.returnOK) {
			var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
			var scriptableStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
	
			inputStream.init(filePicker.file, 0x01, 674, null);//0444 = 674
			scriptableStream.init(inputStream);
	
			accessext_userStylesheet = scriptableStream.read(scriptableStream.available());
			
			//Get rid of newlines
			accessext_userStylesheet = cleanSpaces(accessext_userStylesheet);
			
			if(accessext_userStylesheet != null && accessext_userStylesheet != "") {
				accessext_setCharPref("accessext.styles.userStylesheet.text", accessext_userStylesheet);
			}
	
			scriptableStream.close();
			inputStream.close();
			if (accessext_getBoolPref("accessext.styles.userStylesheet.enable")) {
				//Clear old stylsheet first
				accessext_handle_styles_userStylesheet_enable(false,doc);
				accessext_handle_styles_userStylesheet_enable(true,doc);
			}
		}
	},
	
	accessext_handle_styles_userStylesheet_enable: function(checked,doc) {
		// If adding a style sheet and the style sheet is not empty
		var documentList;
		var headElementList = null;
		var pageDocument    = null;
		var styleElement    = null;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
	
		// Loop through the documents
		for(var i = 0; i < documentList.length; i ++) {
			pageDocument    = documentList[i];
			if (checked && accessext_userStylesheet) {
				headElementList = pageDocument.getElementsByTagName("head");
				styleElement    = pageDocument.createElement("style");
		
				styleElement.setAttribute("id", "_accessextstyles-add-user-styles-sheet");
				styleElement.setAttribute("type", "text/css");
				styleElement.appendChild(pageDocument.createTextNode(accessext_userStylesheet));
		
				// If there is a head element
				if(headElementList.length > 0) {
					headElementList[0].appendChild(styleElement);
				} else { 
					pageDocument.documentElement.childNodes[0].appendChild(styleElement);
				}
			} else {
				accessext_removeStyleSheet("_accessextstyles-add-user-styles-sheet",pageDocument);
			}
		}
		
		//accessext_setBoolPref("accessext.styles.userStylesheet.enable", checked);
	},
	
	/* TODO : Add <acronym> support */
	accessext_handle_expandAbbr: function(checked,doc) {
		var documentList;
		var owner;
		var parent;
		var a;
		var xpathResult;
		var r;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
	
		for (var d = 0; d < documentList.length; d++) {
			var tempDoc = documentList[d];
			if (checked) {
				var abbrs = new Array();
				xpathResult = tempDoc.evaluate("//abbr|//acronym", tempDoc,
					null, XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
				r = xpathResult.iterateNext();
				while (r) {
					abbrs[abbrs.length] = r;
					r = xpathResult.iterateNext();
				}
	
				for (a = 0; a < abbrs.length; a ++) {
					if (abbrs[a].hasAttribute("title")) {
						owner = abbrs[a].ownerDocument;
						parent = abbrs[a].parentNode;
						var clone = abbrs[a].cloneNode(true);
						
						var span = owner.createElement("span");
						span.setAttribute("accessexttype",abbrs[a].tagName.toLowerCase());
						var text = owner.createTextNode(clone.getAttribute("title") + " (");
						span.appendChild(text);
						span.appendChild(clone);
						text = owner.createTextNode(")");
						span.appendChild(text);
						
						parent.replaceChild(span,abbrs[a]);
					}
				}
			} else {
				xpathResult = tempDoc.evaluate("//span[@accessexttype='abbr']|//span[@accessexttype='acronym']", tempDoc,
					null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
				for (var i = 0; i < xpathResult.snapshotLength; i++) {
					var r = xpathResult.snapshotItem(i);
					 a = r.getElementsByTagName(r.getAttribute('accessexttype'));
					if (a.length == 1) {
						r.parentNode.replaceChild(a[0],r);
					} else {
						alert("a.length is " + a.length);
					}
				}
			}
		}
	},
	
	accessext_handle_events: function(item,checked,doc) {
		var events = new Array();
		switch(item) {
			case 'mouse':
				events.push('onclick','onmousedown','onmouseup','onmouseover','onmousemove','onmouseout');
			break;
			case 'keyboard':
				events.push('onkeydown','onkeyup','onkeypress');
			break;
			case 'window':
				events.push('onload','onunload','onabort','onerror','onresize','onscroll');
			break;
			case 'forms':
				events.push('onsubmit','onreset','onselect','onchange','onfocus','onblur');
			break;
		}
		var documentList;
		var pageDocument     = null;
		
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		
		var i;
		for (i=0; i < documentList.length; i++) {
			pageDocument = documentList[i];
			accessext_disable_attributes_recursively(pageDocument.documentElement,events,checked);
		}
		return true;
	},
	
	accessext_handle_TOChighlight: function(item,checked,doc) {
		/* Get all of the TOC elements, will filter later */
		var documentList;
		var i;
		var tocElements = new Array();
		
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
				
		for (i = 0; i < documentList.length; i++) {
			tocElements = tocElements.concat(accessext_getTOCElementsForDoc_helper(
				documentList[i]));
		}
		var mask = 0;
	
		switch (item) {
			case 'main': mask |= LINK_TYPE_MAIN; break;
			case 'secondary': mask |= LINK_TYPE_SECONDARY; break;
			case 'navigation': mask |= LINK_TYPE_NAV; break;
			case 'banner': mask |= LINK_TYPE_BANNER; break;
			case 'all' : mask |= LINK_TYPE_MAIN | LINK_TYPE_SECONDARY | LINK_TYPE_NAV | LINK_TYPE_BANNER;
		}
	
		if (tocElements.length < 1) {
			return false;
		}
	
		for (i = 0; i < tocElements.length; i++) {
			if (tocElements[i].type & mask) {
				accessext_replaceAttributeWBackup(tocElements[i].docNode,"class","accessext_tocElement",checked);
			}
		}
	
		/* Lets see if a stylesheet will do the trick... */
		var url = "chrome://accessext/content/css/toc.css";
		for (i = 0; i < documentList.length; i++) {
			accessext_toggleStyleSheet(checked, url, 'accessext-toc-hidebodytext-stylesheet',documentList[i]);
		}
	
		return true;
	},
	
	/**************************** TABLE MANIPULATORS ****************************/
	
	accessext_mark_tables_helper: function(node,mark,enabled) {
		var aeIdentifier_data_table = "aedt"; // An attribute added to document elements to mark them when we do things like hide layout tables
		//TODO: XPath, eliminate recursion
		if (enabled) {
			if (node.tagName) {
				switch (node.tagName.toLowerCase()) {
					case 'table':
						mark = accessext_isDataTable(node);
					break;
					case 'tr':
					case 'td':
					case 'th':
					case 'tbody':
					case 'thead':
					case 'tfoot':
					case 'caption':
					case 'colgroup':
					case 'col':
						node.setAttribute(aeIdentifier_data_table,mark ? "true" : "false");
					break;
				}
			}
		}
		
		if (node.childNodes) {
			for(var i=0; i<node.childNodes.length; i++) {
				accessext_mark_tables_helper(node.childNodes[i],mark,enabled);
			}
		}
	},
	
	accessext_mark_tables: function(node,enabled) {
		accessext_mark_tables_helper(node,false,enabled);
	},
	
	accessext_handle_styles_tables_enabled: function(checked,doc) {
		var documentList;
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
	
		//Finally, add the stylesheet
		addid='_accessextstyles-disable-layout-tables';
		
		for(var i = 0; i < documentList.length; i++) {
			pageDocument    = documentList[i];
			accessext_mark_tables(pageDocument.documentElement,!checked);
			
			if(checked) {
				accessext_removeStyleSheet(addid,pageDocument);
			} else {
				accessext_addStyleSheet("chrome://accessext/content/css/disable-layout-tables.css", addid,pageDocument);
			}
		}
	},
	
	accessext_getDataTables: function(docElement) {
		var tableElements = docElement.getElementsByTagName('table');
		var ret = new Array();
		var temp;
		for (var i = 0; i < tableElements.length; i++) {
			if (accessext_isDataTable(tableElements[i])) {
				temp = newDataTable(tableElements[i],ret.length);
				ret[ret.length] = temp;
			}
		}
	
		return ret;
	},
	
	accessext_handle_showDataTableTitles: function(checked,doc) {
		var documentList;
		var i;
		var dataTables = new Array();
		
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		
		for (i = 0; i < documentList.length; i++) {
			dataTables = dataTables.concat(accessext_getDataTables(documentList[i].documentElement));
		}
		if (checked) {
			for (i = 0; i < dataTables.length; i++) {
				if (checked) {
					dataTables[i].populateCellsWithHeaders();
				}
			}
		} else if (dataTables.length > 0) {
			//This is considered a static method for now. Refactoring either this or the populate might be the way to go
			for (i = 0; i < documentList.length; i++) {
				dataTables[0].removeCellHeaders(documentList[i]);
			}
		}
	},
	
	accessext_handle_options_accesskeys_disable: function(checked,doc) {
		var documentList;
		var pageDocument     = null;
		var attributes = new Array();
		attributes.push("accesskey");
	
		if((typeof doc != "undefined") && (doc != null)) {
			documentList = doc;
		} else {
			// assume we're doing stuff to the current window
			documentList = accessext_getDocumentsFromActiveBrowser();
		}
		
		for(var i = 0; i < documentList.length; i++) {
			pageDocument = documentList[i];
			accessext_disable_attributes_recursively(pageDocument.documentElement,attributes,checked);
		}
	
	},
	//Interesting : https://bugzilla.mozilla.org/show_bug.cgi?id=83265
	accessext_handle_disableMetaRefresh: function(checked,doc) {
		getActiveBrowser().docShell.allowMetaRedirects = !checked;
		return true;
	},
	
	// Changes whether javascript is enabled on doc
	accessext_handle_disableJavascript: function(checked,doc) {
		getActiveBrowser().docShell.allowJavascript = !checked;
		return true;
	},
});
}});	